package com.cnwidsom.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

public class ClassUtils {
	// 给定类不是目标类的子类
	public static final int CLASS_RELATION_NOT_FOUND = -1;
	// 给定类和目标类相等
	public static final int CLASS_RELATION_SAME = 0;
	// 给定类是目标类的子类
	public static final int CLASS_RELATION_CHILD = 1;

	public static int getRelationBetweenClasses(String sourceClassName, String pClassName) {
		ClassPool pool = ClassPool.getDefault();
		try {
			return getRelationBetweenClasses(pool.get(sourceClassName), pClassName);
		} catch (NotFoundException e) {
			return CLASS_RELATION_NOT_FOUND;
		}
	}

	/**
	 * 查找给定类是否是目标类的子类(或相等)
	 * 
	 * @return
	 */
	public static int getRelationBetweenClasses(CtClass sourceClass, String pClassName) {
		try {
			// 如果两个类名相等,返回same
			if (sourceClass.getName().equals(pClassName)) {
				return CLASS_RELATION_SAME;
			}
			// 如果pClassName是sourceClass实现的接口,返回child
			for (CtClass interfaces : sourceClass.getInterfaces()) {
				if (pClassName.equals(interfaces.getName())) {
					return CLASS_RELATION_CHILD;
				} else {
					if (getRelationBetweenClasses(interfaces, pClassName) != CLASS_RELATION_NOT_FOUND) {
						return CLASS_RELATION_CHILD;
					}
				}
			}
		} catch (NotFoundException e) {
		}

		// 如果sourceClass父类为pClassName,返回child
		try {
			CtClass pClass = sourceClass.getSuperclass();
			if (pClass != null) {
				if (pClassName.equals(pClass.getName())) {
					return CLASS_RELATION_CHILD;
				} else {
					if (getRelationBetweenClasses(pClass, pClassName) != CLASS_RELATION_NOT_FOUND) {
						return CLASS_RELATION_CHILD;
					}
				}
			}
		} catch (NotFoundException e) {
		}

		return CLASS_RELATION_NOT_FOUND;
	}

	public static CtMethod getMatchMethod(CtClass ctClass, String methodName, String[] parameterTypes) throws NotFoundException {
		for (CtMethod method : ctClass.getDeclaredMethods()) {
			if (method.getName().equals(methodName)) {
				Set<String> paramSet = new HashSet<String>();
				for (CtClass ctClassParam : method.getParameterTypes()) {
					boolean isFound = false;
					for (String parameterType : parameterTypes) {
						if (ctClassParam.getName().equals(parameterType)) {
							paramSet.add(ctClassParam.getName());
							isFound = true;
							break;
						}
					}
					if (!isFound) {
						break;
					}
				}
				if (paramSet.size() == parameterTypes.length && paramSet.size() == method.getParameterTypes().length)
					return method;
			}
		}
		return null;
	}

	public static Object getMethod(Class clazz, String methodName, String[] parameters, Object instance, Object[] args) {
		Class[] pclass = null;
		try {
			if (parameters != null && parameters.length == 0) {
				pclass = new Class[parameters.length];
				for (int i = 0; i < parameters.length; i++) {
					String parameter = parameters[i];
					pclass[i] = Class.forName(parameter);
				}
			}
			Method method = clazz.getMethod(methodName, pclass);
			if (instance == null)
				return method;
			else
				return method.invoke(instance, args);
		} catch (ClassNotFoundException e) {
			return null;
		} catch (NoSuchMethodException e) {
			return null;
		} catch (SecurityException e) {
			return null;
		} catch (IllegalAccessException e) {
			return null;
		} catch (IllegalArgumentException e) {
			return null;
		} catch (InvocationTargetException e) {
			return null;
		}
	}
}
